package com.matthicks.macrobot.espn;

import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.matthicks.macrobot.Key;
import com.matthicks.macrobot.RemoteController;

public class QuarkToPDF {
	public static final String PROCESS_NAME = "QuarkXPress.exe";
	
	private int exported = 0;
	
	private RemoteController rc;
	
	public QuarkToPDF() throws UnknownHostException, IOException {
		rc = new RemoteController("pickler.imirus.local", 2600);
	}
	
	public void startQuark() throws InterruptedException {
		if (!rc.isProcessRunning(PROCESS_NAME)) {
			System.out.println("Quark is not running. Starting...");
			
			// Launch shortcut
			rc.keyPress(Key.CONTROL);
			rc.keyPress(Key.ALT);
			rc.keyType(Key.Q);
			rc.keyRelease(Key.ALT);
			rc.keyRelease(Key.CONTROL);
			
			// Wait for process
			if (!rc.waitForProcess(PROCESS_NAME, 30000, true)) {
				throw new RuntimeException("Quark process did not start.");
			}
			
			// Move mouse just in case
			rc.mouseMove(100, 100, 1.0f);
			
			// Wait for screen to appear
			if (rc.screenContains(0, 0, "quark_loaded.png", 2.0f, 10) == null) {
				throw new RuntimeException("Quark was not found on screen.");
			}
			
			System.out.println("Quark launched successfully.");
		} else {
			System.out.println("Quark is already running");
			closeFiles();
		}
	}
	
	public void processDirectoryErrorHandling(File directory) throws InterruptedException {
		do {
			exported = 0;
			try {
				startQuark();
				List<File> store = new ArrayList<File>();
				processDirectory(directory, store);
				System.out.println("Files to process: " + store.size());
				for (int index = 0; index < store.size(); index++) {
					if (store.get(index).length() > 0) {
						processFile(store.get(index), index, store.size());
					} else {
						System.err.println("File is zero length: " + store.get(index).getAbsolutePath() + " (" + (index + 1) + " of " + store.size() + "). Skipping!");
					}
				}
			} catch(Throwable t) {
				t.printStackTrace();
				shutdownQuark();
			}
		} while(exported > 0);
	}
	
	public void processDirectory(File directory, List<File> store) {
		for (File f : directory.listFiles()) {
			if (f.isDirectory()) {
				processDirectory(f, store);
			} else if ((f.getName().toLowerCase().endsWith(".lo")) || (f.getName().toLowerCase().endsWith(".qnet"))) {
//				processFile(f);
				store.add(f);
			} else if ((f.getParentFile().getName().equalsIgnoreCase("Layouts")) && (f.getName().indexOf('.') == -1)) {
//				processFile(f);
				store.add(f);
			}
		}
	}
	
	public void processFile(File file, int index, int total) throws InterruptedException {
		long time = System.currentTimeMillis();
		
		String name = file.getName();
		name = name.replaceAll(",", "_");
		if (!name.equals(file.getName())) {
			System.out.println("\tRenaming from " + file.getName() + " to " + name);
			File n = new File(file.getParentFile(), name);
			file.renameTo(n);
			file = n;
		}
		
		if (name.indexOf('.') > -1) {
			name = name.substring(0, name.indexOf('.'));
		}
		File pdf = new File(file.getParentFile(), name + ".pdf");
		if (pdf.exists()) {
//			System.out.println("File already processed: " + file.getAbsolutePath());
		} else {
			System.out.println("Processing: " + file.getAbsolutePath() + " (" + (index + 1) + " of " + total + ") - " + String.format("%1$tb %1$td %1$tH:%1$tM:%1$tS", Calendar.getInstance()));
			if (openFile(file.getAbsolutePath())) {
				System.out.println("\tOpened");
				if (exportPDF(pdf)) {
					System.out.println("\tExported successfully in " + ((System.currentTimeMillis() - time) / 1000) + " seconds.");
					exported++;
				}
				closeFiles();
			} else {
				System.err.println("\tFailed to open the document, skipping...");
			}
		}
	}
	
	public boolean openFile(String filename) throws InterruptedException {
		// Hot key
		rc.keyPress(Key.CONTROL);
		rc.keyType(Key.o);
		rc.keyRelease(Key.CONTROL);
		
		// Wait for open dialog
		if (rc.screenContains(0, 0, "quark_open_dialog.png", 1.0f, 5) == null) {
			throw new RuntimeException("Open dialog not found!");
		}
		
		// Type filename
		rc.stringType(filename.replaceAll("/", "\\\\"));
		rc.keyType(Key.ENTER);
		
		// Look for "different settings" dialog
		int state;
		while ((state = rc.containsImage("quark_reflow.png", "quark_open_different_settings.png", "quark_open_missing_fonts.png", "quark_error_pict_conversion.png", "quark_cannot_open.png", "quark_out_of_memory.png", "quark_dispatch_xtension.png", "quark_eof.png", "quark_io_error.png", "quark_missing_extension.png", "quark_crashed.png")) != 2) {
			if (state == -1) {
				throw new RuntimeException("Unable to find different settings dialog");
			} else if (state == 0) {
				rc.keyType(Key.ENTER);
				Point p = rc.screenContains(0, 0, "quark_open_different_settings.png", 4.0f, 15);
				if (p == null) {
					throw new RuntimeException("Unable to find different settings dialog");
				}
				rc.keyType(Key.ENTER);
			} else if (state == 1) {
				rc.keyType(Key.ENTER);
			} else if (state == 3) {
				rc.keyType(Key.ENTER);
			} else if (state == 4) {	// Cannot open
				rc.keyType(Key.ENTER);
				return false;
			} else if (state == 5) {	// Out of Memory
				System.err.println("\tOut of memory! Restarting!");
				rc.keyType(Key.ENTER);
				shutdownQuark();
				startQuark();
				return false;
			} else if (state == 6) {	// Missing dispatch xtension
				System.err.println("\tMissing dispatch extension...skipping");
				rc.keyType(Key.ENTER);
				return false;
			} else if (state == 7) {	// EOF
				System.err.println("\tUnexpected end of file. Skipping!");
				rc.keyType(Key.ENTER);
				return false;
			} else if (state == 8) {	// IO error
				System.err.println("\tIO error while loading.");
				rc.keyType(Key.ENTER);
				return false;
			} else if (state == 9) {	// Missing Extension
				System.err.println("\tMissing Extension. Reflow will occur.");
				rc.keyType(Key.ENTER);
			} else if (state == 10) {	// Quark crashed
				System.err.println("\tQuark crashed!");
				rc.keyPress(Key.ALT);
				rc.keyType(Key.D);
				rc.keyRelease(Key.ALT);
				rc.delay(5);
				startQuark();
				return false;
			}
		}
		
		// Look for missing fonts
		Point p = rc.screenContains(0, 0, "quark_open_missing_fonts.png", 4.0f, 15);
		if (p == null) {
			throw new RuntimeException("Unable to find missing fonts dialog");
		}
		rc.keyType(Key.ENTER);
		rc.delay(2.0f);
		rc.keyPress(Key.CONTROL);
		rc.keyType(Key.A);
		rc.keyRelease(Key.CONTROL);
		rc.delay(0.5f);
		rc.keyPress(Key.ALT);
		rc.keyType(Key.e);
		rc.keyRelease(Key.ALT);
		rc.delay(1.0f);
		rc.stringType("myriad pro cond");
		rc.keyType(Key.ENTER);
		rc.delay(1.0f);
		rc.keyType(Key.LEFT);
		rc.delay(0.5f);
		rc.keyType(Key.ENTER);
//		System.out.println("DONE!");
//		rc.mouseMove(p.x, p.y, 1.0f);
//		rc.mouseClick();
		
		// Wait for it to be loaded
		while ((state = rc.containsImage("quark_file_openened.png", "quark_needs_repairs.png", "quark_contrast_pictures.png", "quark_contrast_pictures_warning.png", "quark_error_pict_conversion.png", "quark_text_reflow.png", "quark_missing_pictures.png")) != 0) {
			if (state == -1) {
				throw new RuntimeException("Quark file did not open successfully");
			} else if (state == 1) {
				System.err.println("\tFile needs repairs");
				rc.keyType(Key.ENTER);
			} else if (state == 2) {
				System.err.println("\tFile contains missing pictures that use the Contrast or Negative style.");
				rc.keyType(Key.ENTER);
			} else if (state == 3) {
				System.out.println("\tFound contrast pictures warning dialog.");
				rc.keyType(Key.ENTER);
			} else if (state == 4) {
				System.err.println("\tError PICT conversion.");
				rc.keyType(Key.ENTER);
			} else if (state == 5) {
				System.err.println("\tDifferent fonts cause reflow of text.");
				rc.keyType(Key.ENTER);
			} else if (state == 6) {
				System.err.println("\tMissing pictures from style.");
				rc.keyType(Key.ENTER);
			}
		}
		
		return true;
	}

	public boolean exportPDF(File pdf) {
		// Launch shortcut
		System.out.println("\tLaunching shortcut to export");
		rc.keyPress(Key.CONTROL);
		rc.keyPress(Key.ALT);
		rc.keyType(Key.p);
		rc.keyRelease(Key.ALT);
		rc.keyRelease(Key.CONTROL);
		
		// Wait for export dialog
		if (rc.screenContains(0, 0, "quark_export_dialog.png", 6.0f, 30) == null) {
			throw new RuntimeException("Export screen did not appear");
		}
		rc.stringType(pdf.getName());
		rc.keyType(Key.ENTER);
		
		// Wait for missing pictures dialog
		if (rc.screenContains(0, 0, "quark_export_missing_pictures.png", 4.0f, 15) == null) {
			throw new RuntimeException("Could not find missing pictures dialog");
		}
		rc.keyType(Key.ENTER);
		
		// Wait for save to complete
		long time = System.currentTimeMillis();
		boolean keepWaiting = false;
		do {
			keepWaiting = false;
			if (rc.screenContains(0, 0, "quark_menu_disabled.png", 2.0f, 3) != null) {
				keepWaiting = true;
			} else if (rc.screenContains(200, 200, "quark_exporting_progress.png", 2.0f, 3) != null) {
				keepWaiting = true;
			} else if (rc.screenContains(250, 250, "quark_error_dialog_x.png", 2.0f, 3) != null) {
				rc.keyType(Key.ENTER);
				System.err.println("\tError saving exported file.");
				return false;
			}
			rc.delay(3.0f);
			System.out.println("Waiting for export to finish..." + rc.screenContains(0, 0, "quark_menu_disabled.png", 0.0f, 1) + " - " + rc.screenContains(300, 250, "quark_exporting_progress.png", 0.0f, 1));
			if (System.currentTimeMillis() - time > 180000) {
				System.err.println("Did not finish in the time allowed...continuing anyway.");
				break;
			}
		} while(keepWaiting);
		
		return true;
	}
	
	public void closeFiles() {
		// Closes all open files
		while (rc.screenContains(0, 0, "quark_file_openened.png", 0.0f, 1) != null) {
			rc.keyPress(Key.ALT);
			rc.keyType(Key.f);
			rc.keyRelease(Key.ALT);
			rc.delay(1.0f);
			rc.keyType(Key.c);
			rc.delay(1.0f);
			rc.keyType(Key.n);
			rc.delay(1.0f);
		}
	}
	
	public void shutdownQuark() throws InterruptedException {
		if (rc.isProcessRunning(PROCESS_NAME)) {
			System.out.println("Killing process");
			rc.killProcess(PROCESS_NAME);
			if (!rc.waitForProcess(PROCESS_NAME, 30000, false)) {
				throw new RuntimeException("Process could not be shutdown!");
			}
			System.out.println("Quark was successfully terminated.");
		} else {
			System.out.println("Quark is not running.");
		}
	}
	
	public void disconnect() throws IOException {
		rc.disconnect();
	}
	
	public static void main(String[] args) throws Exception {
//		while (true) {		// Keep trying forever!
//			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2003/"));
//			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2002/"));
//			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2001/"));
//			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2000/"));
			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/1999/"));
			process(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/1998/"));
//		}
		
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2003/"));
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/1998/"));
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/1999/"));
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2000/"));
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2001/"));
//		deletePDFs(new File("//bluemeanie.imirus.local/ftp/imirus - ESPN/espn/2002/"));
	}
	
	private static void deletePDFs(File directory) {
		for (File f : directory.listFiles()) {
			if (f.getName().toLowerCase().endsWith(".pdf")) {
				System.out.println("Deleted " + f.getAbsolutePath() + ": " + f.delete());
			} else if (f.isDirectory()) {
				deletePDFs(f);
			}
		}
	}
	
	public static void process(File directory) throws Exception {
		QuarkToPDF q = new QuarkToPDF();
		try {
			try {
				q.processDirectoryErrorHandling(directory);
			} finally {
				q.shutdownQuark();
			}
		} finally {
			q.disconnect();
		}
	}
}